using System;
using System.Data;
using System.Linq;
using TelerikMvcGridCustomBindingHelper.Mapper;
using TelerikMvcGridCustomBindingHelper.Util;

namespace TelerikMvcGridCustomBindingHelper.ORMIntegration
{
    internal class ORMIntegrationHolder : IDisposable
    {
        public static IsolationLevel TransactionIsolationLevel { get; internal set; }

        public static TransactionBehavior TransactionBehavior { get; internal set; }

        protected readonly IORMIntegration ORMIntegration;

        public ORMIntegrationHolder()
        {
            var ormIntegrationFactory = GridModelMapper.ConfigurationObject.ORMIntegrationFactory;

            if (ormIntegrationFactory != null)
            {
                ORMIntegration = ormIntegrationFactory.Invoke();
            }
        }

        private bool ShouldInitTransactions
        {
            get
            {
                return IsEnabled &&
                    TransactionBehavior == TransactionBehavior.BeginAndCommit ||
                    TransactionBehavior == TransactionBehavior.OnlyBegin;
            }
        }

        public void BeginTransaction()
        {
            if (ShouldInitTransactions)
                ORMIntegration.BeginTransaction(TransactionIsolationLevel);
        }

        private bool ShouldCommitTransactions
        {
            get
            {
                return IsEnabled &&
                    TransactionBehavior == TransactionBehavior.BeginAndCommit ||
                    TransactionBehavior == TransactionBehavior.OnlyCommit;
            }
        }

        public void CommitTransaction()
        {
            if (ShouldCommitTransactions)
                ORMIntegration.CommitTransaction();
        }

        private bool ShouldRollBackTransactions
        {
            get { return ShouldInitTransactions || ShouldCommitTransactions; }
        }

        public void RollBackTransaction()
        {
            if (ShouldRollBackTransactions)
                ORMIntegration.RollBackTransaction();
        }

        public bool IsEnabled
        {
            get { return ORMIntegration != null; }
        }

        public void Dispose()
        {
            if (IsEnabled)
                ORMIntegration.Dispose();
        }

        public IQueryable<TEntity> Query<TEntity>()
        {
            Contract.Expect(() => ORMIntegration)
                .Throw(new InvalidOperationException("Could not find an IORMIntegration implementation."))
                .WhenViolate.IsNotNull();

            var query = ORMIntegration.Query<TEntity>();

            Contract.Expect(() => ORMIntegration)
                .Throw(new InvalidOperationException(string.Format("Failed to create a QueryOver object, please verify the implementation on class \"{0}\".", ORMIntegration.GetType())))
                .WhenViolate.IsNotNull();

            return query;
        }
    }
}